﻿using ArtMath.Attribute;
using ArtMath.Component.Line;
using ArtMath.Converter;
using ArtMath.PointCollection;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using ArtMath.CommonType;
using ArtMath.Core.Data;
using System.Drawing;
using ArtMath.Resource;
using ArtMath.Component.Point;

namespace ArtMath.Component.Angle
{
    /// <summary>
    /// 角基类
    /// </summary>
    [Serializable]
    public abstract class AngleBase : LineBase
    {
        RayBase initialEdge, terminalEdge;
        PropertyDisplayer angleDisplayer;
        public AngleBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            AngleDisplayer = new PropertyDisplayer(this, "Angle");
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "Angle", "Displayer")]
        public PropertyDisplayer AngleDisplayer
        {
            get { return angleDisplayer; }
            set { angleDisplayer = value; }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("InitialEdge")]
        public RayBase InitialEdge
        {
            get { return initialEdge; }
            set
            {
                if (initialEdge is object)
                {
                    initialEdge.InHosts.Remove(this);
                }
                initialEdge = value;
                if (initialEdge is object)
                {
                    initialEdge.InHosts.Add(this);
                }
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("TerminalEdge")]
        public RayBase TerminalEdge
        {
            get { return terminalEdge; }
            set
            {
                if (terminalEdge is object)
                {
                    terminalEdge.InHosts.Remove(this);
                }
                terminalEdge = value;
                if (terminalEdge is object)
                {
                    terminalEdge.InHosts.Add(this);
                }
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("Vertex")]
        public PointBase Vertex
        {
            get { return InPoints[0]; }
            set { InPoints[0] = value; }
        }
        PointCollectionsManager buildPCM(Func<RayBase, PointCollectionsManager> func)
        {
            if (func == null) return null;
            PointCollectionsManager[] mgrs = new PointCollectionsManager[] { func(InitialEdge), func(TerminalEdge) };
            PointCollectionsManager mgr = new PointCollectionsManager(mgrs);
            foreach (PointCollectionBase head1 in mgrs[0].PointCollections)
            {
                foreach (PointCollectionBase head2 in mgrs[1].PointCollections)
                {
                    mgr.ConnectHeads(head1, head2);
                }
            }
            return mgr;
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                return buildPCM((RayBase ray) => { return ray.NewPSkeleton; });
            }
        }

        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                return buildPCM((RayBase ray) => { return ray.NewSkeleton; });
            }
        }

        public override PointCollectionsManager PSkeleton
        {
            get
            {
                return buildPCM((RayBase ray) => { return ray.PSkeleton; });
            }
        }

        public override PointCollectionsManager Skeleton
        {
            get
            {
                return buildPCM((RayBase ray) => { return ray.Skeleton; });
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("Angle"), TypeConverter(typeof(IntelliAngleConverter))]
        public double Angle { get; protected set; }
        [Browsable(false)]
        public virtual double NewAngle
        {
            get { return Angle; }
        }
        public override bool IsEntity
        {
            get
            {
                return false;
            }
        }
        public override bool IsConnectedLineGroup
        {
            get
            {
                return true;
            }
        }
        public override PointD MassPoint
        {
            get
            {
                return InitialEdge.Location;
            }
        }
        [Browsable(false)]
        public override string Formula
        {
            get
            {
                return base.Formula;
            }
        }
        [Browsable(false)]
        public override PropertyDisplayer FormulaDisplayer
        {
            get
            {
                return base.FormulaDisplayer;
            }

            set
            {
                base.FormulaDisplayer = value;
            }
        }
        public override void InChildrenIterator(Predicate<ShapeBase> act)
        {
            if (act == null) return;
            if (InitialEdge != null && !act(InitialEdge)) return;
            if (TerminalEdge != null && !act(TerminalEdge)) return;
        }
        public override void ForEachStraightLine(Predicate<StraightLineBase> act)
        {
            if (act == null) return;
            if (InitialEdge != null && !act(InitialEdge)) return;
            if (TerminalEdge != null && !act(TerminalEdge)) return;
        }
        public override void RefreshPropertyDisplayersLocation()
        {
            AngleDisplayer.RefreshLocation();
            base.RefreshPropertyDisplayersLocation();
        }
        public override void RefreshPropertyDisplayersText()
        {
            AngleDisplayer.RefreshText();
            base.RefreshPropertyDisplayersText();
        }
        public override void PaintProperties(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                AngleDisplayer.Paint(gra);
            }
            base.PaintProperties(gra);
        }
        public override PropertyDisplayer[] PropertyDisplayersCheckNearBy(PointD Plocation)
        {
            List<PropertyDisplayer> res = new List<PropertyDisplayer>(base.PropertyDisplayersCheckNearBy(Plocation));
            if (AngleDisplayer.InRegion(Plocation))
            {
                res.Add(AngleDisplayer);
            }
            return res.ToArray();
        }
        public override void ComponentBuilding(Base component)
        {
            AppendStatus($"{Resources.CommaSeparate}{Resources.Translate("Angle")}{Resources.ColonSeparate}{Pad.ShowRad(Angle)}");
            base.ComponentBuilding(component);
        }
    }
}
